#include "FileTrans.h"
#include "../QCommon/QCommon.h"
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <string>
#include <errno.h>

#define MAX_SOCK_QUEUE 100
#define BUF_SIZE 512
using namespace std;

void* recv_file(void *arg)
{
    FileIn *fileIn=(FileIn*)arg;

    struct sockaddr_in serversock,clientsock;
	serversock.sin_family=AF_INET;
	serversock.sin_addr.s_addr=htons(INADDR_ANY);
	serversock.sin_port=htons(PORT_TCP_IN);
	int socketid;
	if((socketid=socket(AF_INET,SOCK_STREAM,0))==-1)
	{
        cerr<<"Cann't Create Receive Socked!"<<endl;
		abort();
	}
	bind(socketid,(struct sockaddr *)&serversock,sizeof(serversock));
	listen(socketid,MAX_SOCK_QUEUE);
	int clientid,len;
	while(1)
	{
		clientid=accept(socketid,(struct sockaddr *)&clientsock,(socklen_t*)&len);
		    char buf[BUF_SIZE];
		    int len_of_name=FileAskEvent::MAX_LENGTH_FILE_NAME;
            char name[len_of_name];
			read(clientid,name,len_of_name);

			int fd=open(name,O_RDWR|O_CREAT|O_TRUNC,0666);
			write(clientid,"y",sizeof(char));
			int size=0;
			while((size=read(clientid,buf,BUF_SIZE))==BUF_SIZE)
			{
				write(fd,buf,size);
			}
			write(fd,buf,size);
			close(fd);
		    close(clientid);
	}
    return NULL;
}

FileIn& FileIn::getInstance()
{
    static FileIn fileIn;
    return fileIn;
}

FileOut& FileOut::getInstance()
{
    static FileOut fileOut;
    return fileOut;
}

void FileIn::start_recv()
{
    pthread_t tid;
    pthread_create(&tid,NULL,recv_file,this);
}

void* send_file(void *arg)
{
    FileOut *fileOut=(FileOut*)arg;
    char buf[BUF_SIZE];
    while(1)
    {
        if(fileOut->sending.empty())
            continue;
        FileAnswerEvent *event=(FileAnswerEvent*)&fileOut->sending.front();
        fileOut->sending.pop();
        char *filename=event->store_name;
        struct sockaddr_in server;
        server.sin_family=AF_INET;
        server.sin_addr.s_addr=inet_addr(event->dest_ip);
        server.sin_port=htons(PORT_TCP_IN);
        int sockid=socket(AF_INET,SOCK_STREAM,0);
        if(sockid<0)
        {
            cerr<<"Send socket error!"<<endl;
            continue;
        }
        if(connect(sockid,(struct sockaddr *)&server,sizeof(server))==-1)
        {
            cerr<<"Error connect!"<<endl;
            continue;
        }
        write(sockid,filename,strlen(filename)+1);
        char ch;
        read(sockid,&ch,sizeof(char));
        int size=0;
        int fd=open(event->file_name,O_RDONLY);
        while((size=read(fd,buf,BUF_SIZE))==BUF_SIZE)
        {
            write(sockid,buf,size);
        }
        write(sockid,buf,size);
        close(sockid);
    }
    return NULL;
}

void FileOut::start_send()
{
    pthread_t tid;
    pthread_create(&tid,NULL,send_file,this);
}

void FileOut::send(FileAskEvent event)
{
    this->wait.push_back(event);
}

void FileOut::ack(FileAnswerEvent &event)
{
    vector<FileAskEvent>::iterator it;
    for(it=wait.begin();it!=wait.end();it++)
    {
        if((strcmp(it->dest_ip,event.src_ip)==0) && (strcmp(it->file_name,event.file_name)==0))
        {
            if(event.answer_type==allow)
            {
                sending.push(event);
            }
            wait.erase(it);
            break;
        }
    }
}
